package com.angel.bo.common.handler;

import com.angel.bo.common.constant.ReturnCode;
import com.angel.bo.common.exception.BaseException;
import com.angel.bo.common.msg.WebReturn;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

import static org.springframework.http.HttpStatus.*;


/**
 *
 * 功能描述:
 * @author Mei.HaiBo <mail:haibo.mei@ge.com>
 * @date 2019/1/2 15:00
 */
@ControllerAdvice("com.angel.bo")
@RestController
@Slf4j
public class GlobalExceptionHandler implements ErrorController {

    /**
     * 匹配error并处理
     */
    private final static String ERROR_PATH = "/error";

    /**
     * <p>
     * 方法说明:本方法处理Exception抛出异常的情况。
     * 注意GET/POST用错了，SpringMVC的处理也是在异常中展示的，因此需要特殊处理一下
     *
     * @param e        传递的最顶级的异常
     * @param response response对象
     * @return 返回响应
     */
    @ExceptionHandler(Exception.class)
    public WebReturn handle(Exception e, HttpServletResponse response) {
        response.setStatus(HttpStatus.OK.value());
        e.printStackTrace();
        log.error("GlobalExceptionHandler中捕获的异常如下:", e);
        if (e instanceof HttpRequestMethodNotSupportedException) {
            response.setStatus(METHOD_NOT_ALLOWED.value());
            return handle(response);
        } else if (e instanceof HttpMessageNotReadableException) {
            response.setStatus(BAD_REQUEST.value());

            return handle(response);
        } else if (e instanceof BaseException) {
            return new WebReturn(((BaseException) e).getStatus(), e.getMessage());
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            response.setStatus(UNSUPPORTED_MEDIA_TYPE.value());
            return handle(response);
        } else if (e instanceof NullPointerException) {
            return new WebReturn(ReturnCode.NULL_POINT_EXCEPTION);
        }
        return new WebReturn(ReturnCode.SYSTEM_ERROR);
    }

    /**
     * <p>
     * 方法说明:本方法处理除了500之外的所有异常,
     * 注意405错误是被ExceptionHandler转发调用的
     */
    @RequestMapping(ERROR_PATH)
    public WebReturn handle(HttpServletResponse response) {
        WebReturn baseResponse = null;
        log.error("GlobalExceptionHandler中捕获除了500之外的所有状态码: {}" , response.getStatus());
        //根据不同status返回不同消息
        switch (HttpStatus.valueOf(response.getStatus())) {
            //请检查POST/GET方式
            case METHOD_NOT_ALLOWED:
                baseResponse = new WebReturn(ReturnCode.METHOD_ERROR);
                break;
            //请检查JSON格式是否规范
            case BAD_REQUEST:
                baseResponse = new WebReturn(ReturnCode.JSON_DATA_ERROR);
                break;
            //请求头错误
            case UNSUPPORTED_MEDIA_TYPE:
                baseResponse = new WebReturn(ReturnCode.METHOD_ERROR);
                break;
            case NOT_FOUND:
                baseResponse = new WebReturn(ReturnCode.METHOD_NOT_FOUND);
                break;
            default:
                baseResponse = new WebReturn(ReturnCode.SYSTEM_ERROR);
                break;
        }
        //欺骗性质的各种问题均转化为状态置为200
        response.setStatus(HttpStatus.OK.value());
        return baseResponse;
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }
}
